<?php
declare(strict_types=1);

namespace Newbie\Helper;

use App\Admin\Model\System\SystemRole;
use App\Admin\Model\System\SystemUser;
use App\Admin\Service\System\SystemUserService;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Newbie\exception\TokenException;
use Psr\SimpleCache\InvalidArgumentException;

class LoginUser {

    protected string $scene = 'default';

    /**
     * LoginUser constructor.
     * @param string $scene 场景，默认为default
     */
    public function __construct (string $scene = 'default') {
        $this->scene = $scene;
    }

    protected array $parserData = [];

    /**
     * 验证token
     * @param string|null $token
     * @param string $scene
     * @return bool
     */
    public function check (?string $token = null): bool {
        try {
            if ($this->getParserData($token)) {
                return true;
            }
        } catch (InvalidArgumentException $e) {
            throw new TokenException(t('jwt.no_token'));
        } catch (\Throwable $e) {
            throw new TokenException(t('jwt.no_login'));
        }
        return false;
    }


    /**
     * 获取当前登录用户信息
     * @param string|null $token
     * @return array
     */
    public function getUserInfo (?string $token = null): array {
        return $this->getParserData($token);
    }

    protected function getParserData ($token = null): array {
        if ($this->parserData) {
            return $this->parserData;
        }
        if (!$token) {
            $token = request()->header('Token');
        }
        if (empty($token)) {
            throw new TokenException(t('jwt.no_token'));
        }
        JWT::$leeway = 60;//当前时间减去60，把时间留点余地
        $key         = config('app.jwt_key', '123456');
        $headers     = new \stdClass();
        $decoded     = JWT::decode($token, new Key($key, 'HS256'), $headers); //同上的方式，这里要和签发的时候对应
        $data        = json_decode(json_encode($decoded), true);
        if ($data['scene'] != $this->scene) {
            throw  throw new TokenException(t('jwt.validate_fail'));
        }
        $this->parserData = $data['data'];
        return $this->parserData;
    }

    /**
     * 获取当前登录用户ID
     * @return string
     */
    public function getId (): string {
        return strval($this->getParserData()['id']);
    }

    /**
     * 获取当前登录用户名
     * @return string
     */
    public function getUsername (): string {
        if (!$this->parserData) {
            $this->getParserData();
        }
        return $this->parserData['username'];
    }

    /**
     * 获取当前登录用户角色
     * @param array $columns
     * @return array
     */
    public function getUserRole (array $columns = ['id', 'name', 'code']): array {
        return SystemUser::find($this->getId())->roles()->get($columns)->toArray();
    }

    /**
     * 获取当前登录用户岗位
     * @param array $columns
     * @return array
     */
    public function getUserPost (array $columns = ['id', 'name', 'code']): array {
        return SystemUser::find($this->getId())->posts()->get($columns)->toArray();
    }

    /**
     * 获取当前token用户类型
     * @return string
     */
    public function getUserType (): string {
        return $this->parserData['user_type'];
    }

    /**
     * 获取当前token用户部门ID
     * @return int
     */
    public function getDeptId (): int {
        return $this->parserData['dept_id'] ?? 0;
    }

    /**
     * 是否为超级管理员（创始人），用户禁用对创始人没用
     * @return bool
     */
    public function isSuperAdmin (): bool {
        return env('SUPER_ADMIN') == $this->getId();
    }

    /**
     * 是否为管理员角色
     * @return bool
     */
    public function isAdminRole (): bool {
        return in_array(
            SystemRole::find(env('ADMIN_ROLE', 1), ['code'])->code,
            container()->get(SystemUserService::class)->getInfo()['roles']
        );
    }

    /**
     * 获取Token
     * @param Object|array $user
     * @return string
     * @throws InvalidArgumentException
     */
    public function getToken (object|array $user): string {
        $key  = config('app.jwt_key', '123456');         //这里是自定义的一个随机字串，应该写在config文件中的，解密时也会用，相当于加密中常用的 盐-salt
        $data = array(
            "iss"   => 'newbieAdmin',        //签发者 可以为空
            "aud"   => '',          //接收该JWT的一方，可选
            "iat"   => time(),      //签发时间
            "nbf"   => time(),    //在什么时候jwt开始生效  （这里表示生成100秒后才生效）
            "exp"   => time() + 3600 * 24 * 30, //token 过期时间 30天
            'scene' => $this->scene,
            "data"  => [
                'id'       => $user['id'],
                'username' => $user['username'],
                'type'     => $user['user_type']
            ]   //记录的userid的信息，这里是自已添加上去的，如果有其它信息，可以再添加数组的键值对
        );
        return JWT::encode($data, $key, 'HS256'); //同上的方式，这里要和签发的时候对应;
    }

    /**
     * 刷新token
     * @return string
     * @throws InvalidArgumentException
     */
    public function refresh (): string {

    }
}